seo: add schema.org structured data to the five public pages (dogfood 975fdb784275) - #32
Conversation
… 975fdb784275) The leak audit this site sells flags a homepage whose served HTML gives a machine reader nothing to hold onto, so the site's own five public pages must not carry that fault. Each page now carries exactly one application/ld+json block in its head: a @graph with a stable TinyStudio Organization node, a WebSite node, and the page's own WebPage node. Every value is bound to the page's own head metadata - name to the og:title, description to the meta description, url to the og:url - so the structured data cannot drift from what the page actually says. The Organization node is identical across all five pages, no page's block restates a dollar amount (pricing.html owns the price), and no block carries a forbidden promise or a phone number. Adds a source-string CI guard in scripts/check-site.mjs that fails npm test if any public page loses its block, duplicates one, breaks the JSON, mismatches its own metadata, or introduces an extra node.
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
📝 WalkthroughWalkthroughFive public pages now include TinyStudio JSON-LD graphs. ChangesStructured data
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/check-site.mjs`:
- Around line 1125-1133: Update the structured-data validation around the nodes
array to reject graphs whose node count is not exactly three before validating
node types. Preserve the existing uniqueness check and required Organization,
WebSite, and WebPage node validation for valid three-node graphs.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f880bcc7-27d9-4e66-8781-5d6acea5995f
📒 Files selected for processing (6)
public/agents.htmlpublic/audit.htmlpublic/index.htmlpublic/pricing.htmlpublic/specimen.htmlscripts/check-site.mjs
| const nodes = graph["@graph"]; | ||
| const nodeIds = nodes.map((node) => node["@id"]).filter(Boolean); | ||
| if (new Set(nodeIds).size !== nodeIds.length) { | ||
| failures.push(`Structured data on ${pageName} must use unique @id values within the graph.`); | ||
| } | ||
|
|
||
| const orgNodes = nodes.filter((node) => node["@type"] === "Organization"); | ||
| const siteNodes = nodes.filter((node) => node["@type"] === "WebSite"); | ||
| const pageNodes = nodes.filter((node) => node["@type"] === "WebPage"); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reject extra graph nodes.
The validator accepts an @graph that contains the required three nodes plus an arbitrary fourth node. This does not enforce the stated restriction against extra nodes. Require exactly three nodes before validating the node types.
Proposed fix
const nodes = graph["`@graph`"];
+if (nodes.length !== 3) {
+ failures.push(`Structured data on ${pageName} must contain exactly three nodes.`);
+}
const nodeIds = nodes.map((node) => node["`@id`"]).filter(Boolean);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const nodes = graph["@graph"]; | |
| const nodeIds = nodes.map((node) => node["@id"]).filter(Boolean); | |
| if (new Set(nodeIds).size !== nodeIds.length) { | |
| failures.push(`Structured data on ${pageName} must use unique @id values within the graph.`); | |
| } | |
| const orgNodes = nodes.filter((node) => node["@type"] === "Organization"); | |
| const siteNodes = nodes.filter((node) => node["@type"] === "WebSite"); | |
| const pageNodes = nodes.filter((node) => node["@type"] === "WebPage"); | |
| const nodes = graph["`@graph`"]; | |
| if (nodes.length !== 3) { | |
| failures.push(`Structured data on ${pageName} must contain exactly three nodes.`); | |
| } | |
| const nodeIds = nodes.map((node) => node["`@id`"]).filter(Boolean); | |
| if (new Set(nodeIds).size !== nodeIds.length) { | |
| failures.push(`Structured data on ${pageName} must use unique `@id` values within the graph.`); | |
| } | |
| const orgNodes = nodes.filter((node) => node["`@type`"] === "Organization"); | |
| const siteNodes = nodes.filter((node) => node["`@type`"] === "WebSite"); | |
| const pageNodes = nodes.filter((node) => node["`@type`"] === "WebPage"); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/check-site.mjs` around lines 1125 - 1133, Update the structured-data
validation around the nodes array to reject graphs whose node count is not
exactly three before validating node types. Preserve the existing uniqueness
check and required Organization, WebSite, and WebPage node validation for valid
three-node graphs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec92ae8c20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { | ||
| "@type": "Organization", | ||
| "@id": "https://tinystudio.io/#organization", | ||
| "name": "TinyStudio", |
There was a problem hiding this comment.
Reconcile the legacy Agent Desk organization identity
When crawlers reach the publicly served /agent-desk route, public/agent-desk.html:36-44 still declares an Organization named The Tiny Studio with the same https://tinystudio.io/ URL, while this new graph declares it as TinyStudio. This gives machine readers two conflicting identities for the organization the structured data is meant to clarify; update or remove the legacy block and include that served page in the consistency guard.
Useful? React with 👍 / 👎.
This branch sat open long enough for four other public-page PRs (#28 heading hierarchy, #30 apple touch icon, #32 schema.org, #33/#34 links) to land on the same five head sections and the same guard script, so every touched file conflicted. Resolution: all six conflicts were additive, not competing. - The five HTML files each gained a <link rel="canonical"> on this branch and icon/og/twitter/JSON-LD tags on main; both sets are kept. - scripts/check-site.mjs was rebuilt from main's version with this branch's 53-line canonical guard inserted verbatim before the migrations loop, rather than by textually merging two overlapping hunks — the first attempt at that spliced a dangling `const canonicalPages = [` and broke the file. intended-outcome: PR #29 becomes mergeable with the canonical guard and every already-landed head guard both enforced. verify: node scripts/check-site.mjs -> "TinyStudio.io checks passed."; npm test -> 15/15; npm run check, test:headings, test:worker all pass. check:render-blocking is not runnable here (playwright is not installed in this worktree) — CI covers it.
…structured data goes live (2026-08-12) (#140) The deploy-lag item named b004c11 as the pinned release sha with merged PR #32 (schema.org structured data on the five public pages) unreleased. Origin/main is now 56 commits past b004c11 with fa8d83c (#32) in that history; release-state-tinystudio-io.json pins the current main head 18128e8; live / /audit /pricing /agents /specimen each serve exactly one application/ld+json block identical to source; npm run check + npm test pass on the shipped revision and CI is green on main. Acceptance met; nothing further to ship.
What
Closes dogfood finding 975fdb784275 ("Structured data opportunity on home", audit run 20260808T074205Z-msk2fl3n): the home page served no schema.org markup at all, so a machine reader had nothing structured to hold onto.
Following the established pattern for "on home" findings in this repo (meta descriptions PR #21, apple touch icon PR #30, social share PR #31), the fix covers all five public pages, not just home, so the siblings cannot carry the same fault.
Changes
public/index.html,audit.html,agents.html,pricing.html,specimen.html— each head now carries exactly oneapplication/ld+jsonblock: a@graphwithhttps://tinystudio.io/#organization, name/url/logo/description — identical on every page),inLanguage: en),url→ og:url,name→ og:title,description→ meta description,isPartOf→ WebSite,about→ Organization).scripts/check-site.mjs— new "Structured data (dogfood 975fdb784275)" CI guard that failsnpm testif any public page loses its block, duplicates it, breaks the JSON, moves it out of<head>, drifts from its own head metadata, restates a dollar amount off the pricing page, carries a forbidden promise, or captures a phone number.Truthfulness constraints honored
brief-requested.htmlis intentionally excluded (noindex confirmation page, matching all prior guards).Verify
npm run check→ TinyStudio.io checks passednpm test→ headings 6/6, worker, ui all passnpm run check:render-blocking→ all six pages PASS in real Chromium under the production CSP (JSON-LD is a non-executable data block; the audit page already embedsapplication/jsonscripts under the same CSP)npx wrangler deploy --dry-run→ OK (no worker or asset-allowlist change needed; the blocks are inline in the served static files)node --check scripts/check-site.mjsandgit diff --checkcleanSummary by CodeRabbit
New Features
Tests